#include "ogl/font/Effect.h"
#include "mustache.hpp"

Ogl::Font::Effect::Effect()
	:Ogl::Gut::EffectBase(), m_FragMain(Ogl::Font::Effect::DefaultragCode())
{

	m_Shader = std::make_shared<Ogl::Gut::Shader>(Ogl::Font::Effect::VertCode().c_str(), GetFragCode().c_str());
	InitRenderDesc();

}

Ogl::Font::Effect::Effect(const std::string& fragCode)
	:Ogl::Gut::EffectBase(), m_FragMain(fragCode)
{
	InitRenderDesc();
	m_Shader = std::make_shared<Ogl::Gut::Shader>(Ogl::Font::Effect::VertCode().c_str(), GetFragCode().c_str());
}

void Ogl::Font::Effect::InitRenderDesc()
{

	m_BlendDesc.enableBlend = true;
	m_BlendDesc.sfactor = GL_SRC_ALPHA;
	m_BlendDesc.dfactor = GL_ONE_MINUS_SRC_ALPHA;

	m_DepthStencilDesc.enableDepthTest = false;
	m_DepthStencilDesc.enableStencilTest = false;
}

bool Ogl::Font::Effect::RegisterFontFile(const std::string& path)
{
	std::shared_ptr<Ogl::Font::FontLib> fontLib = std::make_shared<Ogl::Font::FontLib>(path);
	if (fontLib->Create() && fontLib->m_Family.size()>0)
	{
		m_FontLibs[fontLib->m_Family] = fontLib;
		return true;
	}

	return false;
}

bool Ogl::Font::Effect::RegisterFontFile(const std::string& path,const std::string& key)
{
	std::shared_ptr<Ogl::Font::FontLib> fontLib = std::make_shared<Ogl::Font::FontLib>(path);

	if (fontLib->Create())
	{
		m_FontLibs[key] = fontLib;
		return true;
	}
	return false;
}

bool Ogl::Font::Effect::HasFontFamily(const std::string& fontFamily)
{
	return m_FontLibs.find(fontFamily) != m_FontLibs.end();
}

std::vector<std::string> Ogl::Font::Effect::GetFamilys()
{
	std::vector<std::string> res;
	for (const auto& it : m_FontLibs)
	{
		res.push_back(it.first);
	}
	return res;
}

std::string Ogl::Font::Effect::GetFragCode()
{
	kainjow::mustache::mustache m1 = FragTemp();
	kainjow::mustache::data d1;
	d1.set("FragMain", m_FragMain);

	return m1.render(d1);
}

void Ogl::Font::Effect::Begin()
{
	Ogl::Gut::EffectBase::Begin();
	m_Shader->Use();
}

void Ogl::Font::Effect::Viewport(const Ogl::Math::Rect& rect)
{
	m_Shader->Use();
	m_Shader->setMat4("projection", rect.GetProj());

}

namespace
{
	std::wstring UTF8ToWString(const std::string& utf8Str) {
		std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
		return converter.from_bytes(utf8Str);
	}
}

void Ogl::Font::Effect::RenderTextLine(const TextLine& inst)
{

	if (HasFontFamily(inst.m_FontFamily))
	{
		
		m_Shader->setVec3("textColor", inst.m_TextColor);
		auto fontLib = m_FontLibs.find(inst.m_FontFamily)->second;
		fontLib->RenderTextMesh(UTF8ToWString(inst.m_Text), inst.m_FontSize, inst.m_Pos.x, inst.m_Pos.y, 1.0f);

	}
}

void Ogl::Font::Effect::End()
{


}


std::string Ogl::Font::Effect::VertCode()
{
	return  R"(
    #version 330 core
layout (location = 0) in vec3 aPos; 
layout (location = 1) in vec3 aNormal; 
layout (location = 2) in vec2 aTex; 

out vec2 TexCoords;

uniform mat4 projection;

void main()
{
    gl_Position = projection * vec4(aPos,1.0);
    TexCoords = aTex;
}
    )";
}

std::string Ogl::Font::Effect::DefaultragCode()
{
	return R"(
uniform vec3 textColor;

void main()
{    
    vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
    color = vec4(textColor, 1.0) * sampled;
}
)";
}

std::string Ogl::Font::Effect::FragTemp()
{
	return R"(
    
    
#version 330 core
in vec2 TexCoords;
out vec4 color;

uniform sampler2D text;

{{FragMain}}

    )";
}
